import 'dart:convert';

import 'package:connectivity/connectivity.dart';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:flutter/cupertino.dart';
import 'package:vc_package/common/common.dart';

import '../../utils/base_sys_utils.dart';
import '../../utils/loading_utils.dart';
import 'http_method.dart';

abstract class BaseHttpManager {
  static int code = 0; // 请求状态码
  static CancelToken cancelToken = CancelToken(); // 取消网络请求 token，默认所有请求都可取消。
  static CancelToken whiteListCancelToken =
      CancelToken(); // 取消网络请求白名单 token，此 token 不会被取消。
  final Map<String, CancelToken> _pendingRequests = {}; // 正在请求列表
  ///登录已失效，请重新登录
  String textLoginExpired();

  ///网络开小差了
  String textNetworkError();

  ///请求失败
  String textRequestError();

  ///模型转Json
  String toJson(data);

  ///json转模型
  Future<T?> getBean<T>(dynamic data);

  ///string转map
  Map<String, dynamic>? getMap(dynamic string);

  ///打印日志
  logInfo({String? tag, String? msg});

  ///保存缓存数据
  Future<void> setSharedData(String sharedUrl, json);

  ///保存缓存数据
  Future<void> invalidAction();

  ///登录失效
  Future<void> loginExpired();

  ///读取缓存数据
  Future<String?> getSharedString(String sharedUrl);

  ///获取基础的Header
  Future<Map<String, dynamic>> getBaseHeader();

  Dio? dio;

  /// request
  request<T>(
    String url, {
    Map? params,
    Map<String, dynamic>? queryParameters,
    HTTPMethod method = HTTPMethod.post,
    bool showDialog = true,
    Map<String, dynamic>? header,
    String? contentType,
    bool isCancelWhiteList = false,
    Options? options,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
    ValueChanged<int>? onError,
    ValueChanged<T?>? onSuccess,
    ValueChanged<T?>? onCache,
  }) async {
    if (showDialog) {
      LoadingUtils.show(data: '加载中...');
    }
    header = header ?? <String, dynamic>{};
    header.addAll(await getBaseHeader());
    var paramsTemp = Map<String, dynamic>.from(params ?? {});
    //没有网络
    var connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.none) {
      var msg = '网络连接失败，请检查网络';
      _onError(onError, 0, errMsg: '网络连接失败，请检查网络');
      LoadingUtils.dismiss();
      LoadingUtils.showInfo(data: msg);
      return BaseResultData(msg, BaseCode.RESULT_ERROR_NETWORK_ERROR).sendMsg();
    }

    if (options != null) {
      options.headers = header;
    } else {
      options = Options(method: method.value);
      options.headers = header;
    }
    options.method = method.value;

    if (!BaseSysUtils.empty(contentType)) {
      options.headers?['Content-Type'] = contentType;
    }

    dio ??= Dio();
    (dio?.httpClientAdapter as IOHttpClientAdapter).onHttpClientCreate =
        (client) {
      client.badCertificateCallback = (cert, host, port) {
        return true;
      };
    };
    Response? response;
    CancelToken requestToken = CancelToken();
    if (dio?.options.extra['cancelDuplicatedRequest'] != true ||
        isCancelWhiteList) {
      if (isCancelWhiteList) {
        requestToken = whiteListCancelToken;
      } else {
        requestToken = cancelToken;
      }
    }
    try {
      response = await dio!.request(
        url,
        options: options,
        // data: FormData.fromMap(paramsTemp),
        queryParameters: paramsTemp,
        // cancelToken: requestToken,
        onReceiveProgress: onReceiveProgress,
        onSendProgress: onSendProgress,
      );
      return response.data;
    } catch (err) {
      DioException error = err as DioException;
      if (error != null) {
        if (error.response?.statusCode == 401) {
          loginExpired();
          LoadingUtils.dismiss();
          return;
        }
        print(err.response.toString());
      }
      logInfo(tag: 'error:', msg: '请求异常url: $url');
      logInfo(tag: 'error:', msg: '请求异常请求头: ${options.headers}');
      logInfo(tag: 'error:', msg: '请求异常参数: $params');
      logInfo(tag: 'error:', msg: "请求异常: ${response?.data}");
      _catchOthersError(BaseCode.RESULT_ERROR_OTHER, onError: onError);
    } finally {
      logInfo(tag: 'Http:', msg: '请求url: $url');
      logInfo(tag: 'Http:', msg: '请求头: ${options.headers}');
      logInfo(tag: 'Http:', msg: '请求参数: $params');
      _dealResponse(response,
          onSuccess: onSuccess, onCache: onCache, onError: onError);
    }
  }

  ///正常返回，数据处理及转换
  _dealResponse<T>(Response? response,
      {ValueChanged<T?>? onSuccess,
      ValueChanged<T?>? onCache,
      ValueChanged<int>? onError}) async {
    try {
      var jsonStr = response?.data;
      if (jsonStr is String) {
        jsonStr = await json.decode(response?.data);
      }
      var jsonMap = <String, dynamic>{};
      jsonMap = Map<String, dynamic>.from(jsonStr);
      logInfo(tag: 'Http:', msg: "返回数据: ${response.toString()}");
      var resultData = BaseResultData.fromJson(jsonMap);
      LoadingUtils.dismiss();
      if (resultData.code != BaseCode.RESULT_OK) {
        onError?.call(resultData.code ?? 0);
        if (resultData.code == BaseCode.RESULT_INVALID &&
            code != BaseCode.RESULT_INVALID) {
          code = resultData.code ?? 0;
          invalidAction();
        } else {
          LoadingUtils.showInfo(data: resultData.desc ?? '');
        }
        return;
      }
      code = resultData.code ?? 0;
      BaseResultData<T> data = BaseResultData(resultData.msg, resultData.code);
      data.data = await getBean<T>(resultData.data);
      onSuccess?.call(data.data);
      onCache?.call(data.data);
    } catch (e) {
      code = 0;
      onError?.call(0);
    }
  }

  ///错误返回
  void _onError(ValueChanged<int>? onError, int code, {String? errMsg}) {
    LoadingUtils.dismiss();
    onError?.call(code);
  }

  /// 处理异常
  void _catchOthersError(int code, {ValueChanged<int>? onError}) {
    LoadingUtils.dismiss();
    onError?.call(code);
    LoadingUtils.showInfo(data: '请求失败,请重试');
  }
}
